#ifndef THINK_THINK_CONSOLE_OUTPUT_FORMATTER_H
#define THINK_THINK_CONSOLE_OUTPUT_FORMATTER_H

static char* think_console_output_formatter =
	"\n"
	"// +----------------------------------------------------------------------\n"
	"// | ThinkPHP [ WE CAN DO IT JUST THINK ]\n"
	"// +----------------------------------------------------------------------\n"
	"// | Copyright (c) 2006~2015 http://thinkphp.cn All rights reserved.\n"
	"// +----------------------------------------------------------------------\n"
	"// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )\n"
	"// +----------------------------------------------------------------------\n"
	"// | Author: yunwuxin <448901948@qq.com>\n"
	"// +----------------------------------------------------------------------\n"
	"namespace think\\console\\output;\n"
	"\n"
	"use think\\console\\output\\formatter\\Stack as StyleStack;\n"
	"use think\\console\\output\\formatter\\Style;\n"
	"\n"
	"class Formatter\n"
	"{\n"
	"\n"
	"    private $decorated = false;\n"
	"    private $styles    = [];\n"
	"    private $styleStack;\n"
	"\n"
	"    /**\n"
	"     * 转义\n"
	"     * @param string $text\n"
	"     * @return string\n"
	"     */\n"
	"    public static function escape($text)\n"
	"    {\n"
	"        return preg_replace(\'/([^\\\\\\\\]?)</is\', \'$1\\\\<\', $text);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 初始化命令行输出格式\n"
	"     */\n"
	"    public function __construct()\n"
	"    {\n"
	"        $this->setStyle(\'error\', new Style(\'white\', \'red\'));\n"
	"        $this->setStyle(\'info\', new Style(\'green\'));\n"
	"        $this->setStyle(\'comment\', new Style(\'yellow\'));\n"
	"        $this->setStyle(\'question\', new Style(\'black\', \'cyan\'));\n"
	"        $this->setStyle(\'highlight\', new Style(\'red\'));\n"
	"        $this->setStyle(\'warning\', new Style(\'black\', \'yellow\'));\n"
	"\n"
	"        $this->styleStack = new StyleStack();\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 设置外观标识\n"
	"     * @param bool $decorated 是否美化文字\n"
	"     */\n"
	"    public function setDecorated($decorated)\n"
	"    {\n"
	"        $this->decorated = (bool) $decorated;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取外观标识\n"
	"     * @return bool\n"
	"     */\n"
	"    public function isDecorated()\n"
	"    {\n"
	"        return $this->decorated;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 添加一个新样式\n"
	"     * @param string $name  样式名\n"
	"     * @param Style  $style 样式实例\n"
	"     */\n"
	"    public function setStyle($name, Style $style)\n"
	"    {\n"
	"        $this->styles[strtolower($name)] = $style;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 是否有这个样式\n"
	"     * @param string $name\n"
	"     * @return bool\n"
	"     */\n"
	"    public function hasStyle($name)\n"
	"    {\n"
	"        return isset($this->styles[strtolower($name)]);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 获取样式\n"
	"     * @param string $name\n"
	"     * @return Style\n"
	"     * @throws \\InvalidArgumentException\n"
	"     */\n"
	"    public function getStyle($name)\n"
	"    {\n"
	"        if (!$this->hasStyle($name)) {\n"
	"            throw new \\InvalidArgumentException(sprintf(\'Undefined style: %s\', $name));\n"
	"        }\n"
	"\n"
	"        return $this->styles[strtolower($name)];\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 使用所给的样式格式化文字\n"
	"     * @param string $message 文字\n"
	"     * @return string\n"
	"     */\n"
	"    public function format($message)\n"
	"    {\n"
	"        $offset   = 0;\n"
	"        $output   = \'\';\n"
	"        $tagRegex = \'[a-z][a-z0-9_=;-]*\';\n"
	"        preg_match_all(\"#<(($tagRegex) | /($tagRegex)?)>#isx\", $message, $matches, PREG_OFFSET_CAPTURE);\n"
	"        foreach ($matches[0] as $i => $match) {\n"
	"            $pos  = $match[1];\n"
	"            $text = $match[0];\n"
	"\n"
	"            if (0 != $pos && \'\\\\\' == $message[$pos - 1]) {\n"
	"                continue;\n"
	"            }\n"
	"\n"
	"            $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));\n"
	"            $offset = $pos + strlen($text);\n"
	"\n"
	"            if ($open = \'/\' != $text[1]) {\n"
	"                $tag = $matches[1][$i][0];\n"
	"            } else {\n"
	"                $tag = isset($matches[3][$i][0]) ? $matches[3][$i][0] : \'\';\n"
	"            }\n"
	"\n"
	"            if (!$open && !$tag) {\n"
	"                // </>\n"
	"                $this->styleStack->pop();\n"
	"            } elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {\n"
	"                $output .= $this->applyCurrentStyle($text);\n"
	"            } elseif ($open) {\n"
	"                $this->styleStack->push($style);\n"
	"            } else {\n"
	"                $this->styleStack->pop($style);\n"
	"            }\n"
	"        }\n"
	"\n"
	"        $output .= $this->applyCurrentStyle(substr($message, $offset));\n"
	"\n"
	"        return str_replace(\'\\\\<\', \'<\', $output);\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * @return StyleStack\n"
	"     */\n"
	"    public function getStyleStack()\n"
	"    {\n"
	"        return $this->styleStack;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 根据字符串创建新的样式实例\n"
	"     * @param string $string\n"
	"     * @return Style|bool\n"
	"     */\n"
	"    private function createStyleFromString($string)\n"
	"    {\n"
	"        if (isset($this->styles[$string])) {\n"
	"            return $this->styles[$string];\n"
	"        }\n"
	"\n"
	"        if (!preg_match_all(\'/([^=]+)=([^;]+)(;|$)/\', strtolower($string), $matches, PREG_SET_ORDER)) {\n"
	"            return false;\n"
	"        }\n"
	"\n"
	"        $style = new Style();\n"
	"        foreach ($matches as $match) {\n"
	"            array_shift($match);\n"
	"\n"
	"            if (\'fg\' == $match[0]) {\n"
	"                $style->setForeground($match[1]);\n"
	"            } elseif (\'bg\' == $match[0]) {\n"
	"                $style->setBackground($match[1]);\n"
	"            } else {\n"
	"                try {\n"
	"                    $style->setOption($match[1]);\n"
	"                } catch (\\InvalidArgumentException $e) {\n"
	"                    return false;\n"
	"                }\n"
	"            }\n"
	"        }\n"
	"\n"
	"        return $style;\n"
	"    }\n"
	"\n"
	"    /**\n"
	"     * 从堆栈应用样式到文字\n"
	"     * @param string $text 文字\n"
	"     * @return string\n"
	"     */\n"
	"    private function applyCurrentStyle($text)\n"
	"    {\n"
	"        return $this->isDecorated() && strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;\n"
	"    }\n"
	"}\n"
	"\n"
;
#endif